#include "Transcode_X264.h"

#define WIDTH 640
#define HEIGHT 480

/**********************************************
函数功能：初始化X264编码器库
函数参数：en   Encode结构体指针     sp  sps_pps结构体指针（存放sps pps内容的）
函数返回值：成功返回0   失败返回-1
**********************************************/
int X264_Iinit(Encode *en, sps_pps *sp)
{
	// 初始化编码器默认属性
	x264_param_default(&en->param);

	// 预设编码库
	x264_param_default_preset(&en->param, "veryfast", "zerolatency");

	// 设置编码器相关属性
	en->param.i_threads = X264_SYNC_LOOKAHEAD_AUTO;		   /* 取空缓冲区继续使用不死锁的保证 */
	en->param.i_sync_lookahead = X264_SYNC_LOOKAHEAD_AUTO; // 自动获取线程超前缓冲区的大小

	// 设置视频属性
	en->param.i_width = WIDTH;		 // 图像的宽度
	en->param.i_height = HEIGHT;	 // 图像的高度
	en->param.i_frame_total = 0;	 //*编码总帧数.不知道用0.
	en->param.i_keyint_min = 0;		 // 关键帧最小间隔
	en->param.i_keyint_max = 60;	 // 关键帧最大间隔   最大2s一个I帧
	en->param.b_annexb = 1;			 // 1前面为0x00000001,0为nal长度
	en->param.b_repeat_headers = 0;	 // 关键帧前面是否放sps跟pps帧，0 否 1，放
	en->param.i_csp = X264_CSP_I422; // 指定输入图像的色彩空间位YUV422--YUYV

	en->param.i_fps_den = 1;	  // 帧率分母     帧率：是用来描述视频中每秒显示的帧数的
	en->param.i_fps_num = 30;	  // 帧率分子     常见的帧率：24   25   30   60
	en->param.i_timebase_num = 1; // 设置每帧时长：1/1000s 也就是每毫秒1帧
	en->param.i_timebase_den = 1000;

	// 设置B帧属性
	en->param.i_bframe = 0;							 // 禁止使用B帧，不进行前后帧参考
	en->param.b_open_gop = 0;						 // 不使用开放式GOP
	en->param.i_bframe_pyramid = 0;					 // 关闭改进B帧预测模式
	en->param.i_bframe_adaptive = X264_B_ADAPT_FAST; // B帧快速自适应模式

	// 设置速率控制参数
	en->param.rc.i_bitrate = 800; // 设置比特率 单位时间发送的比特数量 kbps
	en->param.rc.i_lookahead = 0; // 禁止下一帧预测

	en->param.rc.i_rc_method = X264_RC_ABR; // 码率控制，CQP(恒定质量)， CRF(恒定码率)，ABR(平均码率)
	en->param.rc.i_vbv_max_bitrate = 800;	// 平均码率下，最大瞬时码率，默认0
	en->param.rc.i_vbv_buffer_size = 800;	// VBV Video Buffering Verifier 视频缓存检验器

	// 实例化一个编码器
	en->handle = x264_encoder_open(&en->param);

	// 初始化图像信息
	x264_picture_init(&en->picture);

	// 申请图像空间
	int ret = x264_picture_alloc(&en->picture, X264_CSP_I422, WIDTH, HEIGHT);
	if (ret < 0)
	{
		printf("x264_picture_alloc\n");
		return -1;
	}

	// 获取SPS和PPS
	en->picture.i_pts = 0; // 存放用于整个流的SPS、PPS、SEI
	int pi_nal = 0;		   // 存放NAL单元的个数
	x264_encoder_headers(en->handle, &en->nal, &pi_nal);

	if (pi_nal > 0) // pi_nal=2
	{
		int i = 0;
		for (i = 0; i < pi_nal; i++)
		{
			// 如果获取到的帧类型是SPS
			if (en->nal[i].i_type == NAL_SPS) // SPS数据 0x67&1F   NAL：startcode
			{
				sp->sps = malloc(en->nal[i].i_payload - 4);				// 去掉0x00 00 00 01 的空间大小
				sp->sps_len = en->nal[i].i_payload - 4;					// SPS的NAL去掉0x00  00 00 01的大小
				memcpy(sp->sps, en->nal[i].p_payload + 4, sp->sps_len); // 得到SPS的内容
			}
			/*PPS*/
			if (en->nal[i].i_type == NAL_PPS)
			{
				sp->pps = malloc(en->nal[i].i_payload - 4);
				sp->pps_len = en->nal[i].i_payload - 4;
				memcpy(sp->pps, en->nal[i].p_payload + 4, sp->pps_len);
			}
		}
	}
}

int X264_Encode(Encode *en, unsigned char *cam_buf, int *nal_num)
{
	// 提取yuv分量值
	unsigned char *y = en->picture.img.plane[0]; // y指向picture 的Y分量存储位置
	unsigned char *u = en->picture.img.plane[1]; // u指向picture 的u分量存储位置
	unsigned char *v = en->picture.img.plane[2]; // v指向picture 的v分量存储位置

	unsigned char *frame_ = cam_buf;
	int index_y = 0, index_u = 0, index_v = 0;

	int num = (WIDTH * HEIGHT) * 2; // 图像的字节数  图像的宽*高*2
	int i = 0;
	for (i = 0; i < num; i = i + 4)
	{
		*(y + (index_y++)) = *(frame_ + i);
		*(u + (index_u++)) = *(frame_ + i + 1);
		*(y + (index_y++)) = *(frame_ + i + 2);
		*(v + (index_v++)) = *(frame_ + i + 3);
	}

	// 转码
	x264_picture_t pic_out;
	x264_picture_init(&pic_out);

	int ret = x264_encoder_encode(en->handle, &en->nal, nal_num, &en->picture, &pic_out);
	if (ret < 0)
	{
		printf("x264_encoder_encode\n");
		return -1;
	}

	return 0;
}

int X264_Release(Encode *en, sps_pps *sp)
{

	free(sp->sps);
	free(sp->pps);

	sp->sps = NULL;
	sp->pps = NULL;

	// 清空编码图像
	x264_picture_clean(&en->picture);

	// 关闭编码器
	x264_encoder_close(en->handle);
}

void X264_GetSPS_PPS_Buff(sps_pps *sp, sps_pps_buf *buff)
{
	buff->buf = malloc(sp->sps_len + sp->pps_len + 8);
	int j = 0;
	// 填充SPS  startcode
	buff->buf[j++] = 0x00;
	buff->buf[j++] = 0x00;
	buff->buf[j++] = 0x00;
	buff->buf[j++] = 0x01;
	memcpy(&buff->buf[j], sp->sps, sp->sps_len);
	// 填充PPS   startcode
	j = j + sp->sps_len;
	buff->buf[j++] = 0x00;
	buff->buf[j++] = 0x00;
	buff->buf[j++] = 0x00;
	buff->buf[j++] = 0x01;
	memcpy(&buff->buf[j], sp->pps, sp->pps_len);
	j += sp->pps_len;

	buff->length = j;
}